package com.springcloud.feigndemo.config

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import feign.Logger
import feign.RequestInterceptor
import feign.RequestTemplate
import feign.codec.Decoder
import feign.codec.Encoder
import feign.form.spring.SpringFormEncoder
import org.springframework.beans.factory.ObjectFactory
import org.springframework.boot.autoconfigure.http.HttpMessageConverters
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder
import org.springframework.cloud.openfeign.support.SpringDecoder
import org.springframework.cloud.openfeign.support.SpringEncoder
import org.springframework.context.annotation.Bean

class FeignConfig {

    //如果缺失编码器和解码器则会使用消息转换器

    /*
        这里使用修饰模式,使用Spring Rest中的消息转换器作为参数的SpringEncoder能够使用消息转换器编码Feign方法的形参
        而SpringFormEncoder则提供了对MultipartFile对象编码的支持
     */
    @Bean
    Encoder springEncoder(ObjectFactory<HttpMessageConverters> messageConverters)
    {
       new SpringFormEncoder(new SpringEncoder(messageConverters))
    }

    /*
        解码器
     */

    @Bean
    Decoder decoder(ObjectFactory<HttpMessageConverters> messageConverters)
    {
        new ResponseEntityDecoder(new SpringDecoder(messageConverters))
    }


    @Bean
    ObjectMapper objectMapper()
    {
        new ObjectMapper()
    }

    /*
        SpringMVC支持表单功能能将表单数据映射为pojo,但是Feign并不支持将pojo逆向映射为请求参数
        RequestInterceptor能够将feign的请求拦截,feign会利用消息转换器或编码器将pojo序列化为json、xml等格式的数据放入请求体.这里将feign请求体中映射为请求参数
     */
    @Bean
    RequestInterceptor requestInterceptor()
    {

        new RequestInterceptor() {
            @Override
            void apply(RequestTemplate template) {
                def methodName=template.method()
                switch (methodName)
                {
                    case "GET":
                        if (template.body()!=null)
                        {
                            def node = objectMapper().readTree(template.body())
                            template.body(null)
                            def map=transToMap(node)
                            println(map)
                            template.queries(map)
                        }
                         break
                }
            }

            //将json映射为Map<String, Collection<String>>的闭包
            def transToMap = { JsonNode json ->
                Map<String, Collection<String>> map = new HashMap<>()
                json.fieldNames().forEachRemaining(
                        {
                            name ->
                                def node=json.get(name)
                                def values=new ArrayList<String>()
                                 switch (node.getNodeType())
                                    {
                                        case "ARRAY":
                                            node.forEach(
                                                    {
                                                        v ->
                                                            values.add(v.toString())
                                                    }
                                            )
                                            break
                                        case 'STRING':
                                            values.add(node.asText())
                                            break
                                    }
                                map.put(name, values)
                        }
                )
                map
            }

        }
    }

   @Bean
   Logger.Level level()
   {
       Logger.Level.FULL
   }





/* 当OAuth2 整合Feign时配置

   @Bean
    public OAuth2ClientContext oAuth2ClientContext() {
        return new DefaultOAuth2ClientContext() {
            @Override
            public OAuth2AccessToken getAccessToken() {
                return Optional.ofNullable(super.getAccessToken())
                        .orElse(new DefaultOAuth2AccessToken(
                                ((OAuth2AuthenticationDetails) SecurityContextHolder
                                        .getContext().getAuthentication().getDetails())
                                        .getTokenValue()));
            }
        };
    }

    @Bean
    public OAuth2FeignRequestInterceptor requestInterceptor() {
        return new OAuth2FeignRequestInterceptor(oAuth2ClientContext(), new AuthorizationCodeResourceDetails());
    }




*/



}
